import time
from datetime import datetime
from io import StringIO
from typing import List, Tuple

import psutil
import redis as redis
from sqlalchemy import create_engine, URL, TextClause, text, CursorResult

REDIS = {
    "host": "127.0.0.1",
    "port": 6379,
    "db": 10,
}

params = dict(host=REDIS["host"], port=REDIS["port"], db=REDIS["db"],
              retry_on_timeout=True, socket_connect_timeout=10)

pool: redis.ConnectionPool
redis_conn: redis.Redis


def init_sync_redis_conn():
    global pool, redis_conn
    # 同步连接
    pool = redis.ConnectionPool(**params)
    redis_conn = redis.Redis(connection_pool=pool, decode_responses=True)


init_sync_redis_conn()

pid_list = redis_conn.smembers('pid')

pid_list = [int(item.decode('utf8')) for item in list(pid_list)]

config = {
    "TDENGINE_DATABASE": {
        "host": "server",
        "port": 6030,
        "username": "root",
        "password": "taosdata",
        "database": "nestle_hk",
        "config": "/etc/taos",
        "TIMEZONE": "Asia/Shanghai"
    }
}


class TDEngineWrapper:

    def __init__(self):
        self._engine = create_engine(
            URL.create("taos",
                       username=config["TDENGINE_DATABASE"]["username"],
                       password=config["TDENGINE_DATABASE"]["password"],
                       host=config["TDENGINE_DATABASE"]["host"],
                       port=config["TDENGINE_DATABASE"]["port"],
                       database=config["TDENGINE_DATABASE"]["database"],
                       )
        )

    def connected(self):
        try:
            conn = self._engine.connect()
            conn.close()
            return True
        except Exception as e:
            print(e)
            print(f"和 TDEngine 之间的连接建立失败, 请检查网络是否畅通, 服务器是否正常")
            return False

    def execute(self, statement, parameters=None, *, execution_options=None):
        while not self.connected():
            time.sleep(3)
        with self._engine.begin() as conn:
            if type(statement) is not TextClause:
                statement = text(statement)
            return conn.execute(statement, parameters, execution_options=execution_options)

    @staticmethod
    def rows_to_dict(result: CursorResult, one=False):
        """
        将结果集转成字典
        """
        columns = tuple(map(str, result.keys()))
        rows = result.fetchone() if one else result.fetchall()
        if one:
            return dict(zip(columns, rows))
        return [dict(zip(columns, row)) for row in rows]

    def create_super_table(self,
                           stable: str,
                           ts_field: str,
                           metric_fields: List,
                           tags: List):
        """
        创建超级表
        @stable: 超级表的名称
        @ts_field: 时间戳字段的名称
        @metric_fields: 采集的物理量对应的字段名和类型
        @tags: 标签字段和类型
        """
        if type(metric_fields) is not list:
            raise ValueError("metric_fields 必须是一个列表，里面包含二元组")
        if type(tags) is not list:
            raise ValueError("tags 必须是一个列表，里面包含二元组")
        ddl = f"""
            CREATE STABLE {stable} (
                {ts_field} timestamp,
                {', '.join([' '.join([metric, tp]) for metric, tp in metric_fields])}
            ) TAGS (
                {', '.join([' '.join([tag, tp]) for tag, tp in tags])}
            )
        """
        try:
            self.execute(ddl)
        except Exception as e:
            print(f"超级表建立失败, 错误原因: {e}")
            raise e

    def create_child_table(self, table: str, stable: str, tags_value: Tuple):
        """
        创建子表，必须指定一张超级表
        @table: 子表的名称
        @stable: 超级表的名称
        @tags_value: 标签值, 一个二元组
        """
        ddl = f"""
            CREATE TABLE {table} USING {stable}
            TAGS {tags_value}
        """
        try:
            self.execute(ddl)
        except Exception as e:
            print(f"子表建立失败, 错误原因: {e}")
            raise e

    def td_insert_data(self,
                       table: str,
                       values: List[Tuple],
                       columns: List = None):
        """
        往 tdengine 批量插入数据
        @table: 表名
        @value: 数据
        @columns: 列名
        """
        buf = StringIO()
        for value in values:
            value = list(
                str(item) if isinstance(item, datetime) else "null" if item is None else item
                for item in value
            )
            buf.write(f"({str(value)[1: -1]})")

        query = f"""
            INSERT INTO {config["TDENGINE_DATABASE"]["database"]}.{table} {'(' + ','.join(columns) + ')' if columns is not None else ""} 
            VALUES {buf.getvalue()}
        """

        buf.truncate(0)
        buf.close()
        try:
            print(query)
            self.execute(query)
        except Exception as e:
            print(f"数据插入失败, 错误原因: {e}")
            raise e


tdengine_wrapper = TDEngineWrapper()


def insert_target(pid):
    p = psutil.Process(pid)
    name = p.name()
    status = p.status()
    cpu_percent = p.cpu_percent()
    memory_percent = p.memory_percent()
    rss = p.memory_info().rss / 1024 / 1024  # MB
    read_count = p.io_counters().read_count
    write_count = p.io_counters().write_count
    read_bytes = p.io_counters().read_bytes / 1024 / 1024  # MB
    write_bytes = p.io_counters().write_bytes / 1024 / 1024  # MB
    other_count = p.io_counters().other_count / 1024 / 1024  # MB


# for pid in pid_list:
#    insert_target(pid)


# insert_target(197124)



